home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / LIB / IMPORT.C < prev    next >
C/C++ Source or Header  |  1993-04-10  |  26KB  |  585 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    i m p o r t . c                                                 */
  3. /*                                                                    */
  4. /*    File name mapping routines for UUPC/extended                    */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.             */
  9. /*                                                                    */
  10. /*    Changes Copyright (c) 1990-1993 by Kendra Electronic            */
  11. /*    Wonderworks.                                                    */
  12. /*                                                                    */
  13. /*    All rights reserved except those explicitly granted by the      */
  14. /*    UUPC/extended license agreement.                                */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*
  18.  *    $Id: IMPORT.C 1.3 1993/04/11 00:31:31 dmwatt Exp $
  19.  *
  20.  *    $Log: IMPORT.C $
  21.  *     Revision 1.3  1993/04/11  00:31:31  dmwatt
  22.  *     Global edits for year, TEXT, etc.
  23.  *
  24.  * Revision 1.2  1992/11/22  21:06:14  ahd
  25.  * Correct mapping of dos paths with trailing slashes
  26.  *
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <ctype.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <time.h>
  34.  
  35. #include "lib.h"
  36. #include "import.h"
  37. #include "arbmath.h"
  38. #include "hostable.h"
  39. #include "usertabl.h"
  40. #include "security.h"
  41.  
  42. #define MAX_DIGITS 20         /* Number of digits for arb math */
  43.  
  44. /*--------------------------------------------------------------------*/
  45. /*                    Internal function prototypes                    */
  46. /*--------------------------------------------------------------------*/
  47.  
  48. #define min(x,y) (((x) < (y)) ? (x) : (y))
  49.  
  50. currentfile();
  51.  
  52. /*--------------------------------------------------------------------*/
  53. /*                     Local function prototypes                      */
  54. /*--------------------------------------------------------------------*/
  55.  
  56. static void ImportName( char *local, const char *canon, size_t charsetsize );
  57.  
  58. /*-------------------------------------------------------------------*/
  59. /*                                                                   */
  60. /*   i m p o r t p a t h                                             */
  61. /*                                                                   */
  62. /*   Convert a canonical name to a format the host can handle        */
  63. /*                                                                   */
  64. /*   These routines convert file name between canonical form, which  */
  65. /*   is defined as a 'unix' style pathname, and the MS-DOS all       */
  66. /*   uppercase "xxxxxxxx.xxx" format.                                */
  67. /*                                                                   */
  68. /*   If the canonical name does not have a path, that is the file is */
  69. /*   destined for the local spool directory, we can assume the UNIX  */
  70. /*   name will normally be in a format like this:                    */
  71. /*                                                                   */
  72. /*                                                                   */
  73. /*       X.hostid#######            (Execute files)                  */
  74. /*       C.hostid#######            (Call files)                     */
  75. /*       D.hostid#######            (Data files)                     */
  76. /*                                                                   */
  77. /*   where "hostid" may be most, but not always all, of the local    */
  78. /*   host or remote host (the file came from or is going to) and     */
  79. /*   "######" can be any character valid for the UNIX file system.   */
  80. /*   Note, however, that the routine has to be generic to allow for  */
  81. /*   other file names to be placed in the spool directory without    */
  82. /*   collisions.                                                     */
  83. /*                                                                   */
  84. /*   Avoiding collisions in the spool directory is important; when   */
  85. /*   receiving files with mixed case names longer than 11            */
  86. /*   characters, sooner or later a file name collision will occur.   */
  87. /*                                                                   */
  88. /*   We can also assume that only UUPC will see these names, which   */
  89. /*   means we can transform the name using any method we choose, so  */
  90. /*   long as the UUPC functions opening the file always call         */
  91. /*   importpath, and that importpath is reducible (that is, two      */
  92. /*   calls to importpath with the same argument always yield the     */
  93. /*   same result).  Note that if end user really wanted the file in  */
  94. /*   the spool directory, all he has to do is rename the file-- far  */
  95. /*   better than losing the data because duplicate file names.       */
  96. /*                                                                   */
  97. /*   For these files, we map the name as follows:                    */
  98. /*                                                                   */
  99. /*   0 - If the name is a valid MS-DOS name, use it without changing */
  100. /*                                                                   */
  101. /*   1 - Begin the output name by inserting up to the first eight    */
  102. /*       characters of the remote host name (followed by a slash) as */
  103. /*       a subdirectory name.                                        */
  104. /*                                                                   */
  105. /*   2 - If the input name begins with an uppercase alphabetic       */
  106. /*       character followed by a period, also insert the alphabetic  */
  107. /*       (followed by a slash) to make this a second subdirectory.   */
  108. /*       Then, move the logical start of the input name past the two */
  109. /*       characters.                                                 */
  110. /*                                                                   */
  111. /*   3 - Determine the number of characters the local host and       */
  112. /*       remote hosts have equal to the next characters of the input */
  113. /*       name, up to a maximum of 8, and zero the lower of the two   */
  114. /*       counts.  Then, step past the number of characters of the    */
  115. /*       larger count.                                               */
  116. /*                                                                   */
  117. /*       For example, if the file name is X.keane22222 and the local */
  118. /*       host name is kendra (2 characters match) and the remote     */
  119. /*       host is keane1 (5 characters match), zero the number of     */
  120. /*       characters matched by kendra, and make the new start of the */
  121. /*       file name five characters further (at the first "2").       */
  122. /*                                                                   */
  123. /*   4 - Convert the remaining string using a base conversion, with  */
  124. /*       the input character size being from ascii "#" to ascii "z"  */
  125. /*       (88 characters) to the allowed set of characters in MS-DOS  */
  126. /*       file names (charset, below, 52 characters).                 */
  127. /*                                                                   */
  128. /*   5 - Prepend to the string to be converted the length of the     */
  129. /*       remote host added to the length of the local host           */
  130. /*       multiplied by 8 (both lengths were computed in step 3,      */
  131. /*       above).  The base conversion is also applied to this        */
  132. /*       "character", we which know will be in the range 1-64.       */
  133. /*                                                                   */
  134. /*   6 - If the string created by steps 4 and 5 exceeds 8            */
  135. /*       characters, insert a period after the eighth character to   */
  136. /*       make it a valid MS-DOS file name.  If the string created by */
  137. /*       steps 4 and 5 exceeds 11 characters, truncate the string by */
  138. /*       using the first eight and last three characters.            */
  139. /*                                                                   */
  140. /*   7 - Append the string created in steps 4 through 6 to the path  */
  141. /*       name created in steps 1 and 2.                              */
  142. /*                                                                   */
  143. /*   If the canonical name has a path, it is destined for an end     */
  144. /*   user, so we should not radically transform it like we do for    */
  145. /*   files in the spool directory.  Thus, if the canonical name has  */
  146. /*   a path, mung the canonical file name as follows:                */
  147. /*                                                                   */
  148. /*   1 - skip any path from the canonical name                       */
  149. /*                                                                   */
  150. /*   2 - copy up to 8 character from the canonical name converting . */
  151. /*       to _ and uppercase to lowercase.                            */
  152. /*                                                                   */
  153. /*   3 - if the name was longer than 8 character copy a . to the     */
  154. /*       host name and then copy the up to three characters from     */
  155. /*       the tail of the canonical name to the host name.            */
  156. /*                                                                   */
  157. /*   Note that this set of rules will cause a collision with names   */
  158. /*   that only differ in case, but leaves the name in a recongizable */
  159. /*   format for the user.                                            */
  160. /*-------------------------------------------------------------------*/
  161.  
  162.  
  163. void importpath(char *local, char const *canon, char const *remote)
  164. {
  165.    char *s, *out;
  166.    size_t charsetsize;     /* Number of allowed characters in
  167.                               MS-DOS file names                   */
  168.  
  169.    out = local;
  170.  
  171. /*--------------------------------------------------------------------*/
  172. /*                       Verify our parameters                        */
  173. /*--------------------------------------------------------------------*/
  174.  
  175.    if ( local == NULL )
  176.       panic();
  177.    if ( canon == NULL )
  178.       panic();
  179.  
  180. /*--------------------------------------------------------------------*/
  181. /*                      Define our character set                      */
  182. /*--------------------------------------------------------------------*/
  183.  
  184.     if ( E_charset == NULL )
  185.       E_charset = DOSCHARS;
  186.     charsetsize = strlen( E_charset );
  187.  
  188. /*--------------------------------------------------------------------*/
  189. /*                 Determine if spool file directory                  */
  190. /*--------------------------------------------------------------------*/
  191.  
  192.    if ((s = strrchr(canon, '/')) == (char *)NULL)
  193.    {                          /* File for spooling directory, use
  194.                                  internal character set to avoid
  195.                                  collisons                           */
  196.       static size_t range =  UNIX_END_C - UNIX_START_C + 1;
  197.                               /* Determine unique number characters in
  198.                                  the UNIX file names we are mapping  */
  199.  
  200.       size_t remlen = min(HOSTLEN, strlen(remote));
  201.                               /* Length of the remote name passed
  202.                                  in, shortened below to number of
  203.                                  characters matched in name          */
  204.       size_t nodelen = min(HOSTLEN, strlen(E_nodename));
  205.                               /* Length of the local host name,
  206.                                  shortened below to number of
  207.                                  characters matched in name          */
  208.       size_t subscript = 0;   /* Value of UNIX character to be
  209.                                  converted to MS-DOS character set   */
  210.       char *next        = local + remlen;
  211.       char tempname[FILENAME_MAX];
  212.       unsigned char number[MAX_DIGITS];
  213.                               /* Arbitary length number, for base
  214.                                  conversions                        */
  215.  
  216. /*--------------------------------------------------------------------*/
  217. /*                    Verify we have a remote name                    */
  218. /*--------------------------------------------------------------------*/
  219.  
  220.    if ( remote == NULL )
  221.       panic();
  222.  
  223. /*--------------------------------------------------------------------*/
  224. /*    Put the host name (up to six characters) at the beginning of    */
  225. /*    the MS-DOS file name as a sub-directory name.                   */
  226. /*--------------------------------------------------------------------*/
  227.  
  228.       strncpy(local, remote, remlen);
  229.       *next++ = '/';          /* Add in the sub-directory seperator  */
  230.       s = (char *) canon;     /* Get the beginnging of the UNIX name */
  231.  
  232. /*--------------------------------------------------------------------*/
  233. /*    Files in the spooling directory generally start with "D.",      */
  234. /*    "C.", or "X."; strip off any upper case letter followed by a    */
  235. /*    period into its own directory.                                  */
  236. /*--------------------------------------------------------------------*/
  237.  
  238.       if ((s[0] >= 'A') && (s[0] <= 'Z') && (s[1] == '.'))
  239.       {
  240.          *next++ = *s;        /* Copy the input character            */
  241.          *next++ = '/';       /* Add the sub-directory indicator too */
  242.          s += 2;              /* Step input string past the copied
  243.                                  data                                */
  244.       }
  245.  
  246.       while( remlen > 0 )
  247.       {
  248.          if (equaln(remote,s,remlen))
  249.             break;
  250.          remlen--;
  251.       }
  252.  
  253.       while( nodelen > 0 )
  254.       {
  255.          if (equaln(E_nodename,s,nodelen))
  256.             break;
  257.          nodelen--;
  258.       }
  259.  
  260.       if (nodelen > remlen )
  261.       {
  262.          remlen = 0;
  263.          s += nodelen;
  264.       }
  265.       else {
  266.          nodelen = 0;
  267.          s += remlen;
  268.       }
  269.  
  270.       *next  = '\0';          /* Terminate first part of host string */
  271.  
  272. /*--------------------------------------------------------------------*/
  273. /*       Create a binary number which represents our file name        */
  274. /*--------------------------------------------------------------------*/
  275.  
  276.       for (subscript = 0; subscript < MAX_DIGITS; subscript++ )
  277.          number[subscript] = 0;  /* Initialize number to zero        */
  278.  
  279.       add(number, nodelen + remlen * HOSTLEN, MAX_DIGITS);
  280.                                  /* Append host name info to the
  281.                                     front of the converted string    */
  282.  
  283.       while( (*s != '\0') && (*number == '\0'))
  284.       {
  285.          mult(number, range, MAX_DIGITS); /* Shift the number over   */
  286.          add(number, *s++  - UNIX_START_C , MAX_DIGITS);
  287.                                           /* Add in new low order    */
  288.       } /* while */
  289.  
  290. /*-------------------------------------------------------------------*/
  291. /*   We now have stripped off the leading x. and host name, if any;  */
  292. /*   now, convert the remaining characters in the name by doing a    */
  293. /*   range to charset base conversion.                               */
  294. /*-------------------------------------------------------------------*/
  295.  
  296.       out = &tempname[FILENAME_MAX];
  297.       *--out = '\0';          /* Terminate the string we will build  */
  298.  
  299. /*--------------------------------------------------------------------*/
  300. /*         Here's the loop to actually do the base conversion         */
  301. /*--------------------------------------------------------------------*/
  302.  
  303.       while(adiv( number, charsetsize, &subscript, MAX_DIGITS))
  304.             *--out = E_charset[ subscript ];
  305.  
  306. /*--------------------------------------------------------------------*/
  307. /*    The conversion is done; now squeeze it into an 11 character     */
  308. /*    MS-DOS name with period.                                        */
  309. /*--------------------------------------------------------------------*/
  310.  
  311.       ImportName( next, out, charsetsize);
  312.  
  313.    }
  314.    else {         /* Not file for spooling directory, convert it  */
  315.  
  316.       char *in = (char *) canon;
  317.  
  318. /*--------------------------------------------------------------------*/
  319. /*      Handle leading drive letter (ignore it, assuming valid)       */
  320. /*--------------------------------------------------------------------*/
  321.  
  322.       if ( isalpha( *in ) && (in[1] == ':'))
  323.       {
  324.          *out++ = *in++;      /* The drive letter                    */
  325.          *out++ = *in++;      /* The colon making it a driver letter */
  326.       } /* if */
  327.  
  328.       if ( *in == '/' )       /* Absolute path name?                 */
  329.          *out++ = *in++;      /* Yes, step past it                   */
  330.  
  331.       while( *in == '/')      /* Additional slashes?                 */
  332.          in++;                /* Skip them,  they mean nothing       */
  333.  
  334.       s = strchr( in, '/' );  /* Get end of next path segment        */
  335.  
  336. /*--------------------------------------------------------------------*/
  337. /*              Now convert each simple name in the path              */
  338. /*--------------------------------------------------------------------*/
  339.  
  340.       while ( *in )
  341.       {
  342.          if ( s != NULL )
  343.             *s = '\0';        /* Truncate input string to simple name */
  344.  
  345.          ImportName( out, in , charsetsize );
  346.  
  347.          if ( s == NULL )
  348.             break;
  349.          out = out + strlen( out );
  350.          *out++ = *s++ = '/'; /* Restore path to input and output    */
  351.          in = s;              /* Remember start of this simple name  */
  352.          while( *in == '/')   /* Additional slashes?                 */
  353.             in++;             /* Skip them,  they mean nothing       */
  354.          s = strchr( in , '/' );
  355.       }
  356.  
  357.    } /* else */
  358.  
  359.    printmsg( 3, "ImportPath: Mapped %s to %s", canon, local );
  360.  
  361. } /*importpath*/
  362.  
  363. /*--------------------------------------------------------------------*/
  364. /*    I m p o r t N a m e                                             */
  365. /*                                                                    */
  366. /*    Translate a simple DOS name without the path                    */
  367. /*--------------------------------------------------------------------*/
  368.  
  369. static void ImportName( char *local, const char *canon, size_t charsetsize )
  370. {
  371.  
  372.    char *in = (char *) canon;
  373.    char *out = local;
  374.    size_t len = strlen( canon );
  375.    size_t column;
  376.    char *best_period = NULL;     /* Assume no prince charming         */
  377.  
  378.    if ( strchr(canon,'/') != NULL )
  379.    {
  380.       printmsg(0,"ImportName: Parameter error, not simple name: %s",
  381.             canon);
  382.       panic();
  383.    }
  384.  
  385.    if ( len == 0 )
  386.    {
  387.       printmsg(0,"ImportName: Parameter error, zero length input");
  388.       panic();
  389.    }
  390.  
  391. /*--------------------------------------------------------------------*/
  392. /*                 If a valid DOS name, use it as-is                  */
  393. /*--------------------------------------------------------------------*/
  394.  
  395.    if (ValidDOSName( canon ))
  396.    {
  397.       strcpy( local, canon );
  398.       return;
  399.    }
  400.  
  401. /*--------------------------------------------------------------------*/
  402. /*    If the dataset name has a period, use it.  The rule we          */
  403. /*    follow is use the last period in the second through ninth       */
  404. /*    characters, otherwise use the last period in the dataset        */
  405. /*    name with the exception of leading period.                      */
  406. /*                                                                    */
  407. /*    In any case, we only copy up to eight characters for the        */
  408. /*    dataset name and up to three characters for the extension.      */
  409. /*--------------------------------------------------------------------*/
  410.  
  411.    for ( column = 1; (column < 9) && (in[column] != '\0') ; column++)
  412.    {
  413.       if ( in[column] == '.')
  414.       {
  415.          strncpy( out, in, column + 5 );
  416.                                     /* Period, 3 char extension,
  417.                                        and terminating \0            */
  418.          best_period = &out[column];/* Remember output location of
  419.                                        period in name                */
  420.  
  421.          if ( len > (column + 4) )  /* Need to trunc extension to 3? */
  422.             strcpy( out + column + 1, in + len - 3 ); /* Yes         */
  423.  
  424.          break;
  425.       } /*if */
  426.    }  /* if */
  427.  
  428. /*--------------------------------------------------------------------*/
  429. /*    No period in the first eight characters, search the rest of     */
  430. /*    the name for the last period (unless period is very last        */
  431. /*    character in the string).                                       */
  432. /*--------------------------------------------------------------------*/
  433.  
  434.    if ( best_period == NULL )
  435.    {
  436.  
  437.       strncpy( out , in , 8);
  438.       best_period = strrchr( in+1 , '.');
  439.  
  440.       if ( (best_period != NULL) && (best_period[1] != '\0') )
  441.       {
  442.          strncpy( &out[8], best_period, 4 ); /* Plus period and 3
  443.                                                 in extension         */
  444.  
  445.          if ( strlen( best_period) > 4 )     /* Long Extension?      */
  446.             out[12] = '\0';                  /* Yes --> Truncate     */
  447.  
  448.       } /* if */
  449.       else {                  /* No periods at all, generate one
  450.                                  if needed for long name          */
  451.  
  452.          if ( len > 8 )
  453.          {
  454.             out[8] = '.';
  455.             strcpy(&out[9], in + max(8,(len - 3))  );
  456.          } /* if ( len > 9 ) */
  457.  
  458.       } /* else */
  459.  
  460.       best_period = &out[8];              /* Remember location of
  461.                                              period, okay if past
  462.                                              end of string           */
  463.  
  464.    } /* if ( best_period == NULL ) */
  465.  
  466. /*--------------------------------------------------------------------*/
  467. /*                Now, clean up any invalid characters                */
  468. /*--------------------------------------------------------------------*/
  469.  
  470.    if ( out[ strlen( out ) - 1 ] == '.' ) /* Trailing period?        */
  471.       out[ strlen( out ) - 1 ] = '\0';    /* Just truncate string    */
  472.  
  473.    while( *out != '\0')
  474.    {
  475.       int c ;
  476.       if ( isupper( *out ))
  477.          c = tolower( *out );
  478.       else
  479.          c = *out;
  480.  
  481.       if ((out != best_period) && (strchr( E_charset, c ) == NULL ))
  482.       {
  483.          if ( c > 'z' )
  484.             c -= 62;
  485.          else if ( c > 'Z' )
  486.             c -= 36;
  487.          else if ( c > '9' )
  488.             c -= 10;
  489.          *out = E_charset[ (c - UNIX_START_C) % charsetsize ];
  490.       }
  491.  
  492.       out++;                    /* Step to next character         */
  493.    } /* while( *out != '\0') */
  494.  
  495. /*--------------------------------------------------------------------*/
  496. /*                   Report our results and return                    */
  497. /*--------------------------------------------------------------------*/
  498.  
  499.    printmsg( 5,
  500.             "ImportName: Mapped %s to %s", canon, local );
  501.  
  502. } /* ImportName */
  503.  
  504. /*--------------------------------------------------------------------*/
  505. /*    V a l i d D O S N a m e                                         */
  506. /*                                                                    */
  507. /*    Validate an MS-DOS file name                                    */
  508. /*--------------------------------------------------------------------*/
  509.  
  510. boolean ValidDOSName( const char *s)
  511. {
  512.    char *ptr;
  513.    size_t len = strlen ( s );
  514.    char tempname[FILENAME_MAX];
  515.  
  516. /*--------------------------------------------------------------------*/
  517. /*                      Define our character set                      */
  518. /*--------------------------------------------------------------------*/
  519.  
  520.     if ( E_charset == NULL )
  521.       E_charset = DOSCHARS;
  522.  
  523. /*--------------------------------------------------------------------*/
  524. /*                 Name must be 12 characters or less                 */
  525. /*--------------------------------------------------------------------*/
  526.  
  527.    if (len > 12)
  528.       return FALSE;
  529.  
  530.    strcpy( tempname, s);      /* Make a temp copy we can alter       */
  531.  
  532. /*--------------------------------------------------------------------*/
  533. /*    Simple file name without extension must be eight chracters      */
  534. /*    or less                                                         */
  535. /*--------------------------------------------------------------------*/
  536.  
  537.    ptr = strrchr(tempname, '.');
  538.    if (ptr == NULL)
  539.    {
  540.       if (len > 8)
  541.          return FALSE;
  542.    }
  543.  
  544. /*--------------------------------------------------------------------*/
  545. /*          Period must be in second through ninth character          */
  546. /*--------------------------------------------------------------------*/
  547.  
  548.    else {
  549.       if ((ptr == tempname) || (ptr > &tempname[8]))
  550.          return FALSE;
  551.  
  552. /*--------------------------------------------------------------------*/
  553. /*             Extension must be three characters or less             */
  554. /*--------------------------------------------------------------------*/
  555.  
  556.       if ( strlen( ptr ) > 4) /* Three characters plus the period?   */
  557.          return FALSE;        /* No --> Too much                     */
  558.  
  559. /*--------------------------------------------------------------------*/
  560. /*                          Only one period                           */
  561. /*--------------------------------------------------------------------*/
  562.  
  563.       if (ptr != strchr(tempname, '.'))
  564.          return FALSE;
  565.    } /* else */
  566.  
  567. /*--------------------------------------------------------------------*/
  568. /*                Must only be valid MS-DOS characters                */
  569. /*--------------------------------------------------------------------*/
  570.  
  571.    strlwr( tempname );        /* Map into our desired character set  */
  572.    if ( ptr != NULL )
  573.       *ptr = 'x';             /* We've already accounted for the
  574.                                  period, don't let it ruin our day   */
  575.  
  576.    if (strspn(tempname, E_charset ) == len)
  577.    {
  578.       printmsg(9,"ValidDOSName: \"%s\" is valid", s);
  579.       return TRUE;
  580.    }
  581.    else
  582.       return FALSE;
  583.  
  584. } /* ValidateDOSName */
  585.